import os

import requests
from flask import render_template, request, redirect, url_for, flash, abort
from flask_login import login_required, login_user, logout_user,current_user

from app import app, modles, db, login_manager
from datetime import datetime

from app.view.errors import CustomException

github_client_id = os.getenv('oauth_github_client_id', '')
github_client_secret_id = os.getenv('oauth_github_client_secret', '')


@app.route('/login', methods=['GET'])
def to_login():
    # 已经登录, 则跳转到首页
    if current_user.is_active:
        return redirect(url_for('index'))
    return render_template('login.html')


@app.route('/register', methods=['GET'])
def to_register():
    if current_user.is_active:
        return redirect(url_for('index'))

    return render_template('register.html')


@app.route('/login', methods=['POST'])
def login():
    """登录

    :return:
    """
    form_data = request.form
    username = form_data['username']
    password = form_data['password']
    remember = form_data['remember']

    user = modles.User.query.filter_by(username=username).first()

    if user is None:
        flash('用户不存在')
        return redirect(url_for('to_login'))

    if user.validate_password(password=password):
        login_user(user, remember=remember)  # 登入用户
        flash('登录成功')
        return redirect(url_for('index'))
    else:
        flash('密码错误')
        return redirect(url_for('to_login'))


@app.route('/logout')
@login_required  # 用于视图保护
def logout():
    """注销
    """
    logout_user()  # 登出用户
    flash('注销成功')
    return redirect(url_for('index'))


@app.route('/register', methods=['POST'])
@login_required
def register():
    """注册

    :return:
    """
    username = request.form['username']
    password = request.form['password']
    email = request.form['email']

    # todo 校验用户名, 密码

    user = modles.User.query.filter_by(username=username).first()
    if user:
        flash('改用户名已被注册')
        return redirect(url_for('to_register'))

    user = modles.User(username=username)
    user.set_password(password)
    db.session.add(user)
    db.session.commit()
    flash('注册成功, 请登录')
    return redirect(url_for('to_login'))


@login_manager.user_loader
def load_user(user_id):
    """用户加载回调函数

    :param user_id:
    :return:
    """
    # 注意: 如果 user_id 无效, 则应返回 None 而不是异常
    return modles.User.query.get(int(user_id))


# --------------------- OAuth Login--------------------


@app.route('/oauth')
@login_required
def oauth_login():
    op = request.args.get('op')

    if op == 'github':
        authorize_uri = 'https://github.com/login/oauth/authorize'
        state = int(datetime.now().timestamp())
        redirect_url = f'{authorize_uri}?client_id={github_client_id}&state={state}'
        return redirect(redirect_url)
    else:
        return redirect(url_for('to_login'))


@app.route('/oauth/redirect')
def oauth_redirect():
    """
    第三方 OAuth 重定向返回授权码
    """
    # 判断: 用户同意, 获取 access_token
    code = request.args.get('code')
    if code:
        token = GitHubAPI.get_access_token(code)
        # 获取用户基本信息
        user = GitHubAPI.get_user(token)
        # 判断: 数据库中是否有该用户
        if user:
            # 判断: 用户是否已在系统中注册, 有则登录, 无则先注册后登录
            local_user = modles.User.query.filter_by(oauth_type='github', oauth_uid=user['id']).first()
            if local_user is None:
                local_user = modles.User(username=user['login'], nickname=user['name'], oauth_type='github',
                                         oauth_uid=user['id'])
                # 注册用户
                db.session.add(local_user)
                db.session.commit()
            # 登录用户
            login_user(local_user)
            flash('登录成功')
            # 重定向到首页
            return redirect(url_for('index'))
    else:
        flash('授权登录失败')
        return redirect(url_for('to_login'))


class GitHubAPI:

    @staticmethod
    def get_user(token):
        r = requests.get('https://api.github.com/user',
                         headers={'accept': 'application/json', 'Authorization': f'token {token}'})
        if r.status_code == 200:
            return r.json()

    @staticmethod
    def get_access_token(code):
        data = {
            'client_id': github_client_id,
            'client_secret': github_client_secret_id,
            'code': code
        }

        try:
            r = requests.post('https://github.com/login/oauth/access_token',
                              data=data, headers={'accept': 'application/json'})

            if r.status_code == 200:
                return r.json()['access_token']
        except ConnectionError:
            raise CustomException(410, 'GitHub 连接失败')
